package com.boom.springapp.javafxdemo.utils;

import com.boom.springapp.javafxdemo.MainApplication;
import com.boom.springapp.javafxdemo.common.Stat;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.file.*;
import java.util.*;

@Slf4j
public class GeoExporter {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Data
    public static class UnmatchedRegion {
        public int comments;
        public int users;
        
        public UnmatchedRegion(int comments, int users) {
            this.comments = comments;
            this.users = users;
        }
    }

    public static Map<String, UnmatchedRegion> writeGeoJson(
            Map<String, Stat> statMap,
            String filename,
            String outputDir,
            String videoTitle) {
        
        Map<String, UnmatchedRegion> unmatchedRegions = new HashMap<>();
        
        try {
            // 确保输出目录存在
            Path outputPath = Paths.get(outputDir);
            log.info("输出目录: " + outputPath);
            log.info("输出目录是否存在: " + Files.exists(outputPath));
            
            try {
                Files.createDirectories(outputPath);
                log.info("输出目录已确保存在: " + outputPath);
            } catch (Exception e) {
                log.error("创建输出目录失败: " + e.getMessage());
                return unmatchedRegions;
            }
            
            // 读取模板GeoJSON文件
            Path geoTemplatePath = getGeoJsonTemplatePath();
            log.info("GeoJSON模板路径: " + geoTemplatePath);
            log.info("GeoJSON模板是否存在: " + Files.exists(geoTemplatePath));
            
            if (!Files.exists(geoTemplatePath)) {
                log.error("GeoJSON模板文件不存在: " + geoTemplatePath);
                return unmatchedRegions;
            }
            
            // 确保每个Stat对象都有必要的属性
            for (Map.Entry<String, Stat> entry : statMap.entrySet()) {
                Stat stat = entry.getValue();
                
                if (stat.getUserSexMap() == null) {
                    stat.setUserSexMap(new HashMap<>());
                    if (stat.getUsers() != null && !stat.getUsers().isEmpty()) {
                        for (String userId : stat.getUsers()) {
                            stat.getUserSexMap().put(userId, "保密");
                        }
                    }
                }
                
                stat.recalculateSexStats();
                
                if (stat.getUsers() == null) {
                    stat.setUsers(new HashSet<>());
                }
            }
            
            // 打印统计信息
            log.info("地区统计信息: " + statMap.size() + " 个地区");
            for (Map.Entry<String, Stat> entry : statMap.entrySet()) {
                String location = entry.getKey();
                Stat stat = entry.getValue();
                int userCount = (stat.getUsers() != null) ? stat.getUsers().size() : 0;
                log.info("  " + location + ": " + stat.getLocation() + " 条评论, " + userCount + " 位用户");
            }
            
            // 加载GeoJSON模板
            JsonNode geoJsonData;
            try {
                geoJsonData = objectMapper.readTree(geoTemplatePath.toFile());
                log.info("成功加载GeoJSON模板");
            } catch (Exception e) {
                log.error("加载GeoJSON模板失败: " + e.getMessage());
                return unmatchedRegions;
            }
            
            // 创建地区名称映射
            Map<String, String> locationToFeature = new HashMap<>();
            Map<String, Stat> mergedStats = new HashMap<>();
            
            // 处理每个location进行匹配
            for (Map.Entry<String, Stat> entry : new ArrayList<>(statMap.entrySet())) {
                String location = entry.getKey();
                Stat stat = entry.getValue();
                boolean matched = false;
                
                // 遍历所有feature寻找匹配
                ArrayNode features = (ArrayNode) geoJsonData.get("features");
                for (JsonNode feature : features) {
                    String featureName = feature.get("properties").get("name").asText();
                    String featureFullname = feature.get("properties").has("fullname") ?
                            feature.get("properties").get("fullname").asText() : "";
                    
                    // 简单匹配: location与name/fullname其中之一匹配
                    if (location.equals(featureName) ||
                        location.equals(featureFullname) ||
                        featureName.contains(location) ||
                        location.contains(featureName) ||
                        (featureFullname != null && featureFullname.contains(location))) {
                        
                        matched = true;
                        locationToFeature.put(location, featureName);
                        
                        // 如果已有统计数据，合并
                        if (mergedStats.containsKey(featureName)) {
                            Stat existingStat = mergedStats.get(featureName);
                            existingStat.setLocation(existingStat.getLocation() + stat.getLocation());
                            existingStat.setLike(existingStat.getLike() + stat.getLike());
                            existingStat.setLike(existingStat.getLike() + stat.getLike());
                            
                            // 合并用户集合
                            if (stat.getUsers() != null) {
                                existingStat.getUsers().addAll(stat.getUsers());
                            }
                            
                            // 合并等级统计
                            if (stat.getLevel() != null && existingStat.getLevel() != null &&
                                stat.getLevel().length == existingStat.getLevel().length) {
                                for (int i = 0; i < Math.min(stat.getLevel().length, existingStat.getLevel().length); i++) {
                                    existingStat.getLevel()[i] = existingStat.getLevel()[i] + stat.getLevel()[i];
                                }
                            }
                            
                            // 合并性别统计
                            if (stat.getUserSexMap() != null) {
                                for (Map.Entry<String, String> userEntry : stat.getUserSexMap().entrySet()) {
                                    existingStat.updateUserSex(userEntry.getKey(), userEntry.getValue());
                                }
                            }
                        } else {
                            mergedStats.put(featureName, stat);
                        }
                        
                        break; // 找到匹配后跳出循环
                    }
                }
                
                // 如果未匹配，记录
                if (!matched) {
                    int userCount = (stat.getUsers() != null) ? stat.getUsers().size() : 0;
                    unmatchedRegions.put(location, new UnmatchedRegion(stat.getLocation(), userCount));
                }
            }
            
            // 打印匹配结果
            log.info("地区匹配结果:");
            for (Map.Entry<String, String> entry : locationToFeature.entrySet()) {
                log.info("  " + entry.getKey() + " -> " + entry.getValue());
            }
            
            // 打印未匹配地区
            if (!unmatchedRegions.isEmpty()) {
                log.warn("未匹配地区: " + String.join(", ", unmatchedRegions.keySet()));
            }
            
            // 更新GeoJSON特征的属性
            for (JsonNode feature : geoJsonData.get("features")) {
                ObjectNode properties = (ObjectNode) feature.get("properties");
                String province = properties.get("name").asText();
                Stat stat = mergedStats.get(province);
                
                if (stat != null) {
                    int userCount = (stat.getUsers() != null) ? stat.getUsers().size() : 0;
                    
                    log.info("更新地区数据: " + province + " -> " + stat.getLocation() +
                               "条评论, " + userCount + "位用户");
                    log.info("性别统计: 男 " + stat.getSex().getOrDefault("男", 0) +
                               "人, 女 " + stat.getSex().getOrDefault("女", 0) +
                               "人, 保密 " + stat.getSex().getOrDefault("保密", 0) + "人");
                    
                    // 更新Feature属性
                    properties.put("count", stat.getLocation());
                    properties.put("like", stat.getLike());
                    properties.put("male", stat.getSex().getOrDefault("男", 0));
                    properties.put("female", stat.getSex().getOrDefault("女", 0));
                    properties.put("sexless", stat.getSex().getOrDefault("保密", 0));
                    properties.put("users", userCount);
                    
                    // 更新等级统计
                    if (stat.getLevel() != null && stat.getLevel().length == 7) {
                        properties.put("level0", stat.getLevel()[0]);
                        properties.put("level1", stat.getLevel()[1]);
                        properties.put("level2", stat.getLevel()[2]);
                        properties.put("level3", stat.getLevel()[3]);
                        properties.put("level4", stat.getLevel()[4]);
                        properties.put("level5", stat.getLevel()[5]);
                        properties.put("level6", stat.getLevel()[6]);
                    } else {
                        // 默认值
                        properties.put("level0", 0);
                        properties.put("level1", 0);
                        properties.put("level2", 0);
                        properties.put("level3", 0);
                        properties.put("level4", 0);
                        properties.put("level5", 0);
                        properties.put("level6", 0);
                    }
                } else {
                    // 无数据的地区设为0
                    properties.put("count", 0);
                    properties.put("like", 0);
                    properties.put("male", 0);
                    properties.put("female", 0);
                    properties.put("sexless", 0);
                    properties.put("level0", 0);
                    properties.put("level1", 0);
                    properties.put("level2", 0);
                    properties.put("level3", 0);
                    properties.put("level4", 0);
                    properties.put("level5", 0);
                    properties.put("level6", 0);
                    properties.put("users", 0);
                }
            }
            
            log.info("成功匹配 " + mergedStats.size() + "/" + statMap.size() + " 个地区");
            
            // 保存GeoJSON文件到输出目录
            String geoJsonFilename = filename + ".geojson";
            Path geoJsonOutputPath = outputPath.resolve(geoJsonFilename);
            
            try {
                log.info("正在保存GeoJSON文件到: " + geoJsonOutputPath);
                objectMapper.writerWithDefaultPrettyPrinter()
                           .writeValue(geoJsonOutputPath.toFile(), geoJsonData);
                
                // 验证文件是否真正写入
                if (Files.exists(geoJsonOutputPath)) {
                    long fileSize = Files.size(geoJsonOutputPath);
                    if (fileSize > 0) {
                        log.info("GeoJSON文件保存成功: " + geoJsonOutputPath + " (大小: " + fileSize + " 字节)");
                    } else {
                        log.error("GeoJSON文件为空: " + geoJsonOutputPath);
                        return unmatchedRegions;
                    }
                } else {
                    log.error("GeoJSON文件未创建: " + geoJsonOutputPath);
                    return unmatchedRegions;
                }
            } catch (Exception e) {
                log.error("保存GeoJSON文件失败: " + e.getMessage());
                e.printStackTrace();
                return unmatchedRegions;
            }
            
            // 生成HTML地图，使用相同的输出路径确保一致性
            String titleForHtml = (videoTitle != null) ? videoTitle : filename;
            Path htmlOutputPath = outputPath.resolve(filename + ".html");
            
            try {
                log.info("正在生成HTML地图到: " + htmlOutputPath);
                renderHtml(titleForHtml, geoJsonFilename, htmlOutputPath.toString());
                
                // 验证HTML文件是否生成
                if (Files.exists(htmlOutputPath)) {
                    long fileSize = Files.size(htmlOutputPath);
                    if (fileSize > 0) {
                        log.info("HTML地图生成成功: " + htmlOutputPath + " (大小: " + fileSize + " 字节)");
                    } else {
                        log.error("HTML地图文件为空: " + htmlOutputPath);
                    }
                } else {
                    log.error("HTML地图文件未创建: " + htmlOutputPath);
                }
            } catch (Exception e) {
                log.error("生成HTML地图失败: " + e.getMessage());
                e.printStackTrace();
            }
            
            return unmatchedRegions;
            
        } catch (Exception e) {
            log.error("生成GeoJSON文件过程中发生未预期错误: " + e.getMessage());
            e.printStackTrace();
            return unmatchedRegions;
        }
    }
    
    public static void renderHtml(String title, String geoJsonFilename, String outputPath) throws IOException {
        try {
            Path templatePath = getTemplatePath();
            log.info("HTML模板路径: " + templatePath);
            log.info("HTML模板是否存在: " + Files.exists(templatePath));
            
            if (!Files.exists(templatePath)) {
                log.error("HTML模板文件不存在: " + templatePath);
                throw new FileNotFoundException("HTML模板文件不存在: " + templatePath);
            }
            
            // 读取模板内容
            String templateContent;
            try {
                templateContent = new String(Files.readAllBytes(templatePath), "UTF-8");
                log.info("成功读取HTML模板内容，长度: " + templateContent.length() + " 字符");
            } catch (Exception e) {
                log.error("读取HTML模板失败: " + e.getMessage());
                throw e;
            }
            
            // 替换模板变量
            String htmlContent = templateContent.replace("{{ .Title }}", title)
                                                 .replace("{{ .GeoJsonFile }}", geoJsonFilename);
            log.info("模板变量替换完成，标题: " + title + ", GeoJSON文件: " + geoJsonFilename);
            
            // 保存HTML文件
            try {
                Files.write(Paths.get(outputPath), htmlContent.getBytes("UTF-8"));
                log.info("HTML地图模板渲染完成: " + outputPath);
            } catch (Exception e) {
                log.error("写入HTML文件失败: " + e.getMessage());
                throw e;
            }
            
        } catch (Exception e) {
            log.error("渲染HTML地图失败: " + e.getMessage());
            e.printStackTrace();
            throw e;
        }
    }
    
    // 需要实现获取模板路径的方法
    private static Path getGeoJsonTemplatePath() {
        try {
            return Paths.get(MainApplication.class.getClassLoader()
                    .getResource("china-provinces.geojson").toURI());
        } catch (Exception e) {
            throw new RuntimeException("无法找到geojson模板文件", e);
        }
    }

    private static Path getTemplatePath() {
        try {
            return Paths.get(GeoExporter.class.getClassLoader()
                    .getResource("map_template.html").toURI());
        } catch (Exception e) {
            throw new RuntimeException("无法找到HTML模板文件", e);
        }
    }

}
